﻿namespace lpr
{
    using System;
    using System.IO;
    using System.Reflection;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;

    internal class Shimmy : IDisposable
    {
        private IntPtr _hSimpleLPRNative = IntPtr.Zero;
        private SIMPLELPR_Candidate_brightBackground_get _SIMPLELPR_Candidate_brightBackground_get;
        private SIMPLELPR_Candidate_confidence_get _SIMPLELPR_Candidate_confidence_get;
        private SIMPLELPR_Candidate_country_get _SIMPLELPR_Candidate_country_get;
        private SIMPLELPR_Candidate_element_get _SIMPLELPR_Candidate_element_get;
        private SIMPLELPR_Candidate_numElements_get _SIMPLELPR_Candidate_numElements_get;
        private SIMPLELPR_Candidate_text_get _SIMPLELPR_Candidate_text_get;
        private SIMPLELPR_Candidates_candidate_get _SIMPLELPR_Candidates_candidate_get;
        private SIMPLELPR_Candidates_numCandidates_get _SIMPLELPR_Candidates_numCandidates_get;
        private SIMPLELPR_countryCode_get _SIMPLELPR_countryCode_get;
        private SIMPLELPR_countryFromIdWeight_get _SIMPLELPR_countryFromIdWeight_get;
        private SIMPLELPR_countryFromIdWeight_set _SIMPLELPR_countryFromIdWeight_set;
        private SIMPLELPR_countryFromStringWeight_get _SIMPLELPR_countryFromStringWeight_get;
        private SIMPLELPR_countryFromStringWeight_set _SIMPLELPR_countryFromStringWeight_set;
        private SIMPLELPR_createProcessor _SIMPLELPR_createProcessor;
        private SIMPLELPR_ErrorInfo_description_get _SIMPLELPR_ErrorInfo_description_get;
        private SIMPLELPR_ErrorInfo_errorCode_get _SIMPLELPR_ErrorInfo_errorCode_get;
        private SIMPLELPR_lastError_get _SIMPLELPR_lastError_get;
        private SIMPLELPR_numSupportedCountries_get _SIMPLELPR_numSupportedCountries_get;
        private SIMPLELPR_Processor_analyzeBuffer _SIMPLELPR_Processor_analyzeBuffer;
        private SIMPLELPR_Processor_analyzeFile _SIMPLELPR_Processor_analyzeFile;
        private SIMPLELPR_productKeyFromBuffer_set _SIMPLELPR_productKeyFromBuffer_set;
        private SIMPLELPR_productKeyFromFile_set _SIMPLELPR_productKeyFromFile_set;
        private SIMPLELPR_realizeCountryWeights _SIMPLELPR_realizeCountryWeights;
        private SIMPLELPR_ReferenceCounted_addRef _SIMPLELPR_ReferenceCounted_addRef;
        private SIMPLELPR_ReferenceCounted_release _SIMPLELPR_ReferenceCounted_release;
        private SIMPLELPR_Setup _SIMPLELPR_Setup;

        public Shimmy()
        {
            this._hSimpleLPRNative = IntPtr.Zero;
            this.setup();
        }

        public int Candidate_brightBackground_get(IntPtr hCandidate)
        {
            return this._SIMPLELPR_Candidate_brightBackground_get(hCandidate);
        }

        public float Candidate_confidence_get(IntPtr hCandidate)
        {
            return this._SIMPLELPR_Candidate_confidence_get(hCandidate);
        }

        public string Candidate_country_get(IntPtr hCandidate)
        {
            return Marshal.PtrToStringUni(this._SIMPLELPR_Candidate_country_get(hCandidate));
        }

        public int Candidate_element_get(IntPtr hCandidate, uint id, out SIMPLELPR_Element pElem)
        {
            return this._SIMPLELPR_Candidate_element_get(hCandidate, id, out pElem);
        }

        public uint Candidate_numElements_get(IntPtr hCandidate)
        {
            return this._SIMPLELPR_Candidate_numElements_get(hCandidate);
        }

        public string Candidate_text_get(IntPtr hCandidate)
        {
            return Marshal.PtrToStringUni(this._SIMPLELPR_Candidate_text_get(hCandidate));
        }

        public IntPtr Candidates_candidate_get(IntPtr hCandidates, uint id)
        {
            return this._SIMPLELPR_Candidates_candidate_get(hCandidates, id);
        }

        public uint Candidates_numCandidates_get(IntPtr hCandidates)
        {
            return this._SIMPLELPR_Candidates_numCandidates_get(hCandidates);
        }

        private void cleanup()
        {
            if (this._hSimpleLPRNative != IntPtr.Zero)
            {
                FreeLibrary(this._hSimpleLPRNative);
                this._hSimpleLPRNative = IntPtr.Zero;
            }
        }

        public int countryCode_get(IntPtr hEngine, uint id, out string ppcwsCode)
        {
            IntPtr ptr;
            int num = this._SIMPLELPR_countryCode_get(hEngine, id, out ptr);
            ppcwsCode = (num > 0) ? Marshal.PtrToStringUni(ptr) : null;
            return num;
        }

        public int countryFromIdWeight_get(IntPtr hEngine, uint id, out float pfWeight)
        {
            return this._SIMPLELPR_countryFromIdWeight_get(hEngine, id, out pfWeight);
        }

        public int countryFromIdWeight_set(IntPtr hEngine, uint id, float fWeight)
        {
            return this._SIMPLELPR_countryFromIdWeight_set(hEngine, id, fWeight);
        }

        public int countryFromStringWeight_get(IntPtr hEngine, string id, out float fWeight)
        {
            return this._SIMPLELPR_countryFromStringWeight_get(hEngine, id, out fWeight);
        }

        public int countryFromStringWeight_set(IntPtr hEngine, string id, float fWeight)
        {
            return this._SIMPLELPR_countryFromStringWeight_set(hEngine, id, fWeight);
        }

        public IntPtr createProcessor(IntPtr hEngine)
        {
            return this._SIMPLELPR_createProcessor(hEngine);
        }

        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            this.cleanup();
        }

        public string ErrorInfo_description_get(IntPtr hErrInfo)
        {
            return Marshal.PtrToStringUni(this._SIMPLELPR_ErrorInfo_description_get(hErrInfo));
        }

        public uint ErrorInfo_errorCode_get(IntPtr hErrInfo)
        {
            return this._SIMPLELPR_ErrorInfo_errorCode_get(hErrInfo);
        }

        ~Shimmy()
        {
            this.Dispose(false);
        }

        [DllImport("kernel32.dll")]
        private static extern IntPtr FreeLibrary(IntPtr library);
        [DllImport("kernel32.dll", CharSet=CharSet.Ansi)]
        private static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
        public IntPtr lastError_get(IntPtr hEngine, uint bClear)
        {
            return this._SIMPLELPR_lastError_get(hEngine, bClear);
        }

        [DllImport("kernel32.dll")]
        private static extern IntPtr LoadLibrary(string lpFileName);
        public uint numSupportedCountries_get(IntPtr hEngine)
        {
            return this._SIMPLELPR_numSupportedCountries_get(hEngine);
        }

        private void pin<T>(ref T del) where T: class
        {
            Type t = typeof(T);
            Delegate delegateForFunctionPointer = Marshal.GetDelegateForFunctionPointer(GetProcAddress(this._hSimpleLPRNative, t.Name), t);
            del = delegateForFunctionPointer as T;
        }

        public IntPtr Processor_analyzeBuffer(IntPtr hProcessor, IntPtr pcvImgData, uint widthStep, uint width, uint height, uint maxCharHeight)
        {
            return this._SIMPLELPR_Processor_analyzeBuffer(hProcessor, pcvImgData, widthStep, width, height, maxCharHeight);
        }

        public IntPtr Processor_analyzeFile(IntPtr hProcessor, string pcwsImgPath, uint maxCharHeight)
        {
            return this._SIMPLELPR_Processor_analyzeFile(hProcessor, pcwsImgPath, maxCharHeight);
        }

        public int productKeyFromBuffer_set(IntPtr hEngine, IntPtr key, uint keySize)
        {
            return this._SIMPLELPR_productKeyFromBuffer_set(hEngine, key, keySize);
        }

        public int productKeyFromFile_set(IntPtr hEngine, string productKeyPath)
        {
            return this._SIMPLELPR_productKeyFromFile_set(hEngine, productKeyPath);
        }

        public int realizeCountryWeights(IntPtr hEngine)
        {
            return this._SIMPLELPR_realizeCountryWeights(hEngine);
        }

        public void ReferenceCounted_addRef(IntPtr hObj)
        {
            if (this._hSimpleLPRNative != IntPtr.Zero)
            {
                this._SIMPLELPR_ReferenceCounted_addRef(hObj);
            }
        }

        public void ReferenceCounted_release(IntPtr hObj)
        {
            if (this._hSimpleLPRNative != IntPtr.Zero)
            {
                this._SIMPLELPR_ReferenceCounted_release(hObj);
            }
        }

        [DllImport("kernel32.dll")]
        private static extern void SetDllDirectory(string lpFileName);
        private void setup()
        {
            if (this._hSimpleLPRNative == IntPtr.Zero)
            {
                string codeBase = Assembly.GetExecutingAssembly().CodeBase;
                if (codeBase.StartsWith("file://"))
                {
                    codeBase = codeBase.Remove(0, 8);
                }
                string str2 = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "native");
                bool flag = IntPtr.Size == 4;
                string str3 = Path.Combine(str2, flag ? "x86" : "x64");
                string lpFileName = Path.Combine(str3, "filter_native.dll");
                SetDllDirectory(str3);
                this._hSimpleLPRNative = LoadLibrary(lpFileName);
                if (this._hSimpleLPRNative == IntPtr.Zero)
                {
                    throw new Exception("dll not found");
                }
                this.pin<SIMPLELPR_ReferenceCounted_addRef>(ref this._SIMPLELPR_ReferenceCounted_addRef);
                this.pin<SIMPLELPR_ReferenceCounted_release>(ref this._SIMPLELPR_ReferenceCounted_release);
                this.pin<SIMPLELPR_ErrorInfo_errorCode_get>(ref this._SIMPLELPR_ErrorInfo_errorCode_get);
                this.pin<SIMPLELPR_ErrorInfo_description_get>(ref this._SIMPLELPR_ErrorInfo_description_get);
                this.pin<SIMPLELPR_Candidate_text_get>(ref this._SIMPLELPR_Candidate_text_get);
                this.pin<SIMPLELPR_Candidate_country_get>(ref this._SIMPLELPR_Candidate_country_get);
                this.pin<SIMPLELPR_Candidate_confidence_get>(ref this._SIMPLELPR_Candidate_confidence_get);
                this.pin<SIMPLELPR_Candidate_brightBackground_get>(ref this._SIMPLELPR_Candidate_brightBackground_get);
                this.pin<SIMPLELPR_Candidate_numElements_get>(ref this._SIMPLELPR_Candidate_numElements_get);
                this.pin<SIMPLELPR_Candidate_element_get>(ref this._SIMPLELPR_Candidate_element_get);
                this.pin<SIMPLELPR_Candidates_numCandidates_get>(ref this._SIMPLELPR_Candidates_numCandidates_get);
                this.pin<SIMPLELPR_Candidates_candidate_get>(ref this._SIMPLELPR_Candidates_candidate_get);
                this.pin<SIMPLELPR_Processor_analyzeBuffer>(ref this._SIMPLELPR_Processor_analyzeBuffer);
                this.pin<SIMPLELPR_Processor_analyzeFile>(ref this._SIMPLELPR_Processor_analyzeFile);
                this.pin<SIMPLELPR_numSupportedCountries_get>(ref this._SIMPLELPR_numSupportedCountries_get);
                this.pin<SIMPLELPR_countryCode_get>(ref this._SIMPLELPR_countryCode_get);
                this.pin<SIMPLELPR_countryFromIdWeight_get>(ref this._SIMPLELPR_countryFromIdWeight_get);
                this.pin<SIMPLELPR_countryFromStringWeight_get>(ref this._SIMPLELPR_countryFromStringWeight_get);
                this.pin<SIMPLELPR_countryFromIdWeight_set>(ref this._SIMPLELPR_countryFromIdWeight_set);
                this.pin<SIMPLELPR_countryFromStringWeight_set>(ref this._SIMPLELPR_countryFromStringWeight_set);
                this.pin<SIMPLELPR_realizeCountryWeights>(ref this._SIMPLELPR_realizeCountryWeights);
                this.pin<SIMPLELPR_lastError_get>(ref this._SIMPLELPR_lastError_get);
                this.pin<SIMPLELPR_createProcessor>(ref this._SIMPLELPR_createProcessor);
                this.pin<SIMPLELPR_productKeyFromFile_set>(ref this._SIMPLELPR_productKeyFromFile_set);
                this.pin<SIMPLELPR_productKeyFromBuffer_set>(ref this._SIMPLELPR_productKeyFromBuffer_set);
                this.pin<SIMPLELPR_Setup>(ref this._SIMPLELPR_Setup);
            }
        }

        public IntPtr Setup()
        {
            return this._SIMPLELPR_Setup();
        }

        private delegate int SIMPLELPR_Candidate_brightBackground_get(IntPtr hCandidate);

        private delegate float SIMPLELPR_Candidate_confidence_get(IntPtr hCandidate);

        private delegate IntPtr SIMPLELPR_Candidate_country_get(IntPtr hCandidate);

        private delegate int SIMPLELPR_Candidate_element_get(IntPtr hCandidate, uint id, [MarshalAs(UnmanagedType.Struct)] out Shimmy.SIMPLELPR_Element pElem);

        private delegate uint SIMPLELPR_Candidate_numElements_get(IntPtr hCandidate);

        private delegate IntPtr SIMPLELPR_Candidate_text_get(IntPtr hCandidate);

        private delegate IntPtr SIMPLELPR_Candidates_candidate_get(IntPtr hCandidates, uint id);

        private delegate uint SIMPLELPR_Candidates_numCandidates_get(IntPtr hCandidates);

        private delegate int SIMPLELPR_countryCode_get(IntPtr hEngine, uint id, out IntPtr ppcwsCode);

        private delegate int SIMPLELPR_countryFromIdWeight_get(IntPtr hEngine, uint id, [MarshalAs(UnmanagedType.R4)] out float pfWeight);

        private delegate int SIMPLELPR_countryFromIdWeight_set(IntPtr hEngine, uint id, float fWeight);

        private delegate int SIMPLELPR_countryFromStringWeight_get(IntPtr hEngine, [MarshalAs(UnmanagedType.LPWStr)] string id, [MarshalAs(UnmanagedType.R4)] out float fWeight);

        private delegate int SIMPLELPR_countryFromStringWeight_set(IntPtr hEngine, [MarshalAs(UnmanagedType.LPWStr)] string id, float fWeight);

        private delegate IntPtr SIMPLELPR_createProcessor(IntPtr hEngine);

        [StructLayout(LayoutKind.Sequential, Pack=8)]
        public struct SIMPLELPR_Element
        {
            [MarshalAs(UnmanagedType.R4)]
            public float fConfidence;
            public Shimmy.SIMPLELPR_Rect boundingBox;
            public char glyph;
        }

        private delegate IntPtr SIMPLELPR_ErrorInfo_description_get(IntPtr hErrInfo);

        private delegate uint SIMPLELPR_ErrorInfo_errorCode_get(IntPtr hErrInfo);

        private delegate IntPtr SIMPLELPR_lastError_get(IntPtr hEngine, uint bClear);

        private delegate uint SIMPLELPR_numSupportedCountries_get(IntPtr hEngine);

        private delegate IntPtr SIMPLELPR_Processor_analyzeBuffer(IntPtr hProcessor, IntPtr pcvImgData, uint widthStep, uint width, uint height, uint maxCharHeight);

        private delegate IntPtr SIMPLELPR_Processor_analyzeFile(IntPtr hProcessor, [MarshalAs(UnmanagedType.LPWStr)] string pcwsImgPath, uint maxCharHeight);

        private delegate int SIMPLELPR_productKeyFromBuffer_set(IntPtr hEngine, IntPtr key, uint keySize);

        private delegate int SIMPLELPR_productKeyFromFile_set(IntPtr hEngine, [MarshalAs(UnmanagedType.LPWStr)] string productKeyPath);

        private delegate int SIMPLELPR_realizeCountryWeights(IntPtr hEngine);

        [StructLayout(LayoutKind.Sequential, Pack=8)]
        public struct SIMPLELPR_Rect
        {
            public int left;
            public int top;
            public int width;
            public int height;
        }

        private delegate void SIMPLELPR_ReferenceCounted_addRef(IntPtr hObj);

        private delegate void SIMPLELPR_ReferenceCounted_release(IntPtr hObj);

        private delegate IntPtr SIMPLELPR_Setup();
    }
}

